local skynet = require "skynet"
local filelog = require "filelog"
local msghelper = require "ranklistsvrhelper"
local timetool = require "timetool"
local tabletool = require "tabletool"
local redisdao = require "dao.redisdao"
local timer = require "timer"
local configdao = require "configdao"
local base = require "base"
local json = require "cjson"
json.encode_sparse_array(true,1,1)
--[[
	rank_data ={
		rid  = 0,
		rankval = 0,
		rolename = "",
		logo ="",
		sex = 0,
		updatalasttime = ""
		gamenumber = 0,
		mttnumber  = 0,
		lastreftime  = 0, 最后刷新时间

	}

--]]
local ranklistcfg = nil
local ranklist = nil
local RanklistRedisMng = {}

--稳定排名
function RanklistRedisMng.get_tpl_rankstable_key(rank_key, region)
--	filelog.sys_error("稳定排名RanklistRedisMng.get_tpl_rank_key", region)
	if rank_key == ERankListType.ERANKLISTTYPE_GMNUMBER_COMMON and region ~= nil and region ~= 0 then
		return "TPL_RANK_STABLE"..region
	end

	if rank_key == ERankListType.ERANKLISTTYPE_GMNUMBER_MATCH and region ~= nil  and region ~= 0 then
		return "TPL_RANK_STABLE_MATCH"..region
	end

 	return "TPL_RANK_STABLE"..rank_key

end

--稳定排名备份数据
function RanklistRedisMng.get_tpl_rankstable_key_copy(rank_key, region)
--	filelog.sys_error("稳定排名RanklistRedisMng.get_tpl_rank_key", region)
	if rank_key == ERankListType.ERANKLISTTYPE_GMNUMBER_COMMON and region ~= nil and region ~= 0 then
		return "TPL_RANK_STABLE_COPY"..region
	end

	if rank_key == ERankListType.ERANKLISTTYPE_GMNUMBER_MATCH and region ~= nil  and region ~= 0 then
		return "TPL_RANK_STABLE_MATCH_COPY"..region
	end

 	return "TPL_RANK_STABLE_COPY"..rank_key

end


--实时排名数据
function RanklistRedisMng.get_tpl_rank_key(rank_key, region)
 	return "TPL_RANK_"..rank_key.."_REGION_"..region

end


function RanklistRedisMng.get_tpl_playerinfo_key(rank_key, region)	
	return "TPL_PLAYERINFO_"..rank_key.."_REGION_"..region	
end

--存放重置操作时间
function RanklistRedisMng.get_tpl_ref_key(rank_key, region)
	return "TPL_REF_"..rank_key.."_REGION_"..region
end


-- @des    上报排行榜实时数据
-- @para   updaterankinfo(rank_key,rid...)
function RanklistRedisMng.update_realtimedata(updaterankinfo)
	--参数检查
	if not RanklistRedisMng.isok_para_updaterankinfo(updaterankinfo) then
		filelog.sys_error("update_realtimedata error")
		return
	end

	local rank_key 			= updaterankinfo.rank_key --排行榜类型
	local rankval_addtype 	= updaterankinfo.rankval_addtype --1更新 2直接覆盖数据
	local rankval 			= updaterankinfo.rankval
	
	local result    		= nil
	local rank_data 		= {}
	local data 				= {}
	
	result,data = redisdao.query_data(msghelper:get_conf().ranklistdb.svr_id,
		"hget", RanklistRedisMng.get_tpl_playerinfo_key(rank_key, (updaterankinfo.region or 0)), updaterankinfo.rid)
	if result and data ~= nil then
		rank_data = json.decode(data)
		if rankval_addtype == 1 and rankval > 0 then 

			--处理是否重置
			if ranklistcfg[rank_key].is_userefresh_time 
				and  rank_data.lastreftime - RanklistRedisMng.get_reftime(rank_key, (updaterankinfo.region or 0)) < 0 then			
				rank_data.rankval = 0
				rank_data.lastreftime =  timetool.get_time()
			end

			rankval = rank_data.rankval + rankval
		end
		rank_data.gamenumber = rank_data.gamenumber + updaterankinfo.addgamenumber
		rank_data.mttnumber = rank_data.mttnumber + updaterankinfo.addmttnumber

	else
		rank_data.gamenumber =  updaterankinfo.addgamenumber
		rank_data.mttnumber  =  updaterankinfo.addmttnumber
		rank_data.lastreftime =  timetool.get_time()
	end
	

	--更新排行榜数据
	if rankval > 0 then
		--判断是否符合进榜条件
		if rankval < ranklistcfg[rank_key].rankval_limit then
			return 
		end

		redisdao.save_data(msghelper:get_conf().ranklistdb.svr_id,
			"zadd", RanklistRedisMng.get_tpl_rank_key(rank_key, (updaterankinfo.region or 0)),
			rankval, updaterankinfo.rid
		)
	end


	--更新玩家信息
	rank_data.updatalasttime = timetool.get_time()
	if rankval > 0 then
		rank_data.rankval = rankval
	end
	rank_data.rolename = updaterankinfo.rolename
	rank_data.logo     = updaterankinfo.logo
	rank_data.sex      = updaterankinfo.sex
	rank_data.rid      = updaterankinfo.rid

	redisdao.save_data(msghelper:get_conf().ranklistdb.svr_id,
			"hset", RanklistRedisMng.get_tpl_playerinfo_key(rank_key, (updaterankinfo.region or 0)),
			 updaterankinfo.rid, json.encode(rank_data)
		)

end

--@des  获取排名
function RanklistRedisMng.get_ranklist(rank_key,begin, num, region)
	if ranklistcfg[rank_key].is_realtime then
		return RanklistRedisMng.get_ranklist_realtime(rank_key, begin, num, region)
	end
	return RanklistRedisMng.get_ranklist_stable(rank_key, begin, num, region)
end

-- @des    获得非实时排名
function RanklistRedisMng.get_ranklist_stable(rank_key,begin, num, region)
	--参数检查
	local result, ranks = redisdao.query_data(msghelper:get_conf().ranklistdb.svr_id,
			"zrevrange", RanklistRedisMng.get_tpl_rankstable_key(rank_key, region),
			begin, begin+num-1, "WITHSCORES"
		)
	if not result then
		filelog.sys_error("RanklistRedisMng.get_ranklist", ranks)
		return nil
	end

	local ranklist 	= {}
	local rank 		= 0
	local rank_data	
	local rank_msg 	
	local last_rank = 0
	local rankcfgitem = ranklistcfg[rank_key]
	for i = 1, #ranks, 2 do
		result, rank_data = redisdao.query_data(msghelper:get_conf().ranklistdb.svr_id,
		"hget", RanklistRedisMng.get_tpl_playerinfo_key(rank_key, region), ranks[i])
		if result and rank_data ~= nil and not rankcfgitem.blacklist[rank_data.rid] then
			rank_data = json.decode(rank_data)
			rank = rank + 1
			num = num - 1

			rank_msg 	= {}
			rank_msg.rid        = rank_data.rid
			rank_msg.rank 		= rank
			rank_msg.rankval 	= ranks[i + 1]
			rank_msg.rolename 	= rank_data.rolename
			rank_msg.logo 		= rank_data.logo
			rank_msg.sex 		= rank_data.sex
			table.insert(ranklist, rank_msg)
			if num <= 0 then
				return
			end			
		else
			filelog.sys_error("get_ranklist_stable error", #ranks)
		end
	end
	return ranklist
end



-- @des    获得实时排名
function RanklistRedisMng.get_ranklist_realtime(rank_key,begin, num, region)
	local result, ranks = redisdao.query_data(msghelper:get_conf().ranklistdb.svr_id,
			"zrevrange", RanklistRedisMng.get_tpl_rank_key(rank_key, region or 0),
			begin, begin+num+30, "WITHSCORES"
		)
	if not result then
		filelog.sys_error("RanklistRedisMng.get_ranklist", ranks)
		return nil
	end
	local ranklist 	= {}
	local rank 		= 0
	local rank_data	
	local rank_msg 	
	local last_rank = 0
	local rankcfgitem = ranklistcfg[rank_key]
	for i = 1, #ranks, 2 do
		result, rank_data = redisdao.query_data(msghelper:get_conf().ranklistdb.svr_id,
		"hget", RanklistRedisMng.get_tpl_playerinfo_key(rank_key, region), ranks[i])
		if result and rank_data ~= nil and not rankcfgitem.blacklist[rank_data.rid] then
			rank_data = json.decode(rank_data)
			rank = rank + 1
			num = num - 1

			rank_msg 	= {}
			rank_msg.rid        = rank_data.rid
			rank_msg.rank 		= rank
			rank_msg.rankval 	= ranks[i + 1]
			rank_msg.rolename 	= rank_data.rolename
			rank_msg.logo 		= rank_data.logo
			rank_msg.sex 		= rank_data.sex
			table.insert(ranklist, rank_msg)
			if num <= 0 then
				break
			end			
		else
			filelog.sys_error("get_ranklist_realtime error", #ranks)
		end
	end
	return ranklist

end


-- @des    定时实时排名到稳定排名
function RanklistRedisMng.update_realrank_tostablerank(rank_key,startkey,remainNum,region)
	--删除稳定排名表数据
	if startkey == 0 then
		RanklistRedisMng.delete_stablerank_data(rank_key, region)
	end

	local result,rk = redisdao.query_data(msghelper:get_conf().ranklistdb.svr_id,
			"zscan", RanklistRedisMng.get_tpl_rank_key(rank_key, region),startkey)

	if not result then
		filelog.sys_error("RanklistRedisMng.update_realrank_tostablerank error")
		return nil
	end



	if #rk ~= 2 then
		filelog.sys_error("#rk ~= 2")
		return
	end
	startkey = tonumber(rk[1])
	local ranks = rk[2]

	local  rank_data	
	local  isTrue = true
	for i = 1, #ranks, 2 do
		local key 		= ranks[i]
		local rankval 	= tonumber(ranks[i + 1])

		if remainNum <= 0 then
			isTrue = false
			break
		end
		
		--判断是否符合进榜条件
		if rankval < ranklistcfg[rank_key].rankval_limit then
			--删除原来数据
			RanklistRedisMng.delete_playerinfo_data(rank_key,key, region)
		else
			if RanklistRedisMng.isupdate_tostablerank(rank_key,key, region) then
				if rankval > 0 then
					redisdao.save_data(msghelper:get_conf().ranklistdb.svr_id,
						"zadd", RanklistRedisMng.get_tpl_rankstable_key(rank_key, region),
						rankval, key)
					remainNum = remainNum - 1
				end
			end

		end
	end



	if startkey > 0 and  remainNum > 0 then
		 RanklistRedisMng.update_realrank_tostablerank(rank_key,startkey,remainNum, adress_gps)
	end
end


-- @des    判断是否将该玩家排名更新到稳定排名中
function RanklistRedisMng.isupdate_tostablerank(rank_key,rid, region)
	local result 
	local rank_data	
	local isUp = false

	local rankcfgitem = ranklistcfg[rank_key]

	if not rankcfgitem.blacklist[rid] then
		return false
	end

	if rankcfgitem.whitelist[rid] then
		return true
	end

	if rankcfgitem.is_openotherctrl then		
		--活跃度
		--判断是否放入稳定排名
		result, rank_data = redisdao.query_data(msghelper:get_conf().ranklistdb.svr_id,
		"hget", RanklistRedisMng.get_tpl_playerinfo_key(rank_key, region), rid)
		if result and rank_data ~= nil then
			rank_data = json.decode(rank_data)
			local updatalasttime = rank_data.updatalasttime
			local gamenumber     = rank_data.gamenumber
			local mttnumber      = rank_data.mttnumber

			local nowtime = timetool.get_time()
			local num = timetool.get_diff_day(updatalasttime, nowtime)

			if num <= rankcfgitem.maxgamedays 
				and (gamenumber >= rankcfgitem.mingamenumber 
					or mttnumber >= rankcfgitem.minmttnumber ) then
				isUp = true
			end

			--白名单
			if not isUp then
				if rankcfgitem.whitelist[rid] then
					isUp = true
				end
			end

		end
	else
		isUp = true
	end

	return isUp
end

function RanklistRedisMng.init()
	RanklistRedisMng.init_rankconf()

	if ranklistcfg == nil then
		return
	end

	--设置间隔更新定时器
	RanklistRedisMng.set_timer()

	--设置重置定时器
	RanklistRedisMng.set_reftimer()
end


-- @des    定时
function RanklistRedisMng.set_timer()	
	for _, v in pairs(ranklistcfg) do		
		RanklistRedisMng.set_timer_ranktype(v.rank_key)
	end
end


-- @des    定时根据每个排名类型
function RanklistRedisMng.set_timer_ranktype(rank_key)

	if not ranklistcfg[rank_key].is_useupspacetime then
		return
	end

	local nowtime = timetool.get_time()
	local uptime = timetool.get_str_timestamp(ranklistcfg[rank_key].uptime)

	if uptime < nowtime then
		uptime = uptime + 86400 
	end
	local interval = uptime - nowtime

	local upspacetime = ranklistcfg[rank_key].upspacetime
	--定时
	local timermsg = {rank_key = rank_key,upsptime = upspacetime}
	timer.settimer(interval*100, "timeing_uprank", timermsg)		
end



-- @des    重置
function RanklistRedisMng.set_reftimer()
	for i,v in pairs(ranklistcfg) do
		RanklistRedisMng.set_timer_refranktype(v.rank_key)
	end
end



-- @des    重置根据每个排名类型
function RanklistRedisMng.set_timer_refranktype(rank_key)

	if not ranklistcfg[rank_key].is_userefresh_time then
		return
	end

	local interval = RanklistRedisMng.get_refreshtime(ranklistcfg[rank_key].refreshtime) 

	local upspacetime = ranklistcfg[rank_key].refreshspacetime
	--定时
	local timermsg = {rank_key = rank_key,upsptime = upspacetime}
	timer.settimer(interval*100, "timeing_refrank", timermsg)
end



-- @des    配置
function RanklistRedisMng.init_rankconf()
	--读取配置文件
	if ranklistcfg == nil then
		ranklistcfg = configdao.get_business_conf(100, 1000, "ranklistcfg")
		if ranklistcfg ~= nil then
			ranklistcfg = ranklistcfg.ranklistcfg
		end
	end

	if ranklistcfg == nil then
		filelog.sys_error("RanklistRedisMng.upatedata ranklistcfg == nil")
		return
	end

end


-- @des    更新参数检查
-- @return true 参数ok false参数异常
function RanklistRedisMng.isok_para_updaterankinfo(updaterankinfo)
	if updaterankinfo.rank_key == nil or ranklistcfg[updaterankinfo.rank_key] == nil then
		return false
	end

	if updaterankinfo.rid == nil or updaterankinfo.rid == 0 then
		return false
	end

	if updaterankinfo.rankval_addtype == nil 
		or updaterankinfo.rankval == nil
		or updaterankinfo.rolename == nil
		or updaterankinfo.logo == nil
		or updaterankinfo.sex == nil
		or updaterankinfo.addgamenumber == nil
		or updaterankinfo.addmttnumber == nil then
		return false
	end
	return true
end



-- @des    删除一个玩家数据
function RanklistRedisMng.delete_playerinfo_data(rank_key,rid, region)
	redisdao.save_data(msghelper:get_conf().ranklistdb.svr_id,
			"zrem", RanklistRedisMng.get_tpl_rank_key(rank_key, region),rid)

	redisdao.save_data(msghelper:get_conf().ranklistdb.svr_id,
			"hdelt", RanklistRedisMng.get_tpl_playerinfo_key(rank_key, region),rid)
end



-- @des    删除实时排名数据
function RanklistRedisMng.delete_rank_data(rank_key, region)

	redisdao.save_data(msghelper:get_conf().ranklistdb.svr_id,
			"del", RanklistRedisMng.get_tpl_rank_key(rank_key, region))


	RanklistRedisMng.save_reftime(rank_key,timetool.get_time(), region)
end

-- @des    删除非实时排名数据
function RanklistRedisMng.delete_stablerank_data(rank_key, region)

	redisdao.save_data(msghelper:get_conf().ranklistdb.svr_id,
			"del", RanklistRedisMng.get_tpl_rankstable_key(rank_key, region))

end

-- @des    获得非实时排行榜元素个数
function RanklistRedisMng.get_stablerank_datanum(rank_key, region)

	local result,rk = redisdao.query_data(msghelper:get_conf().ranklistdb.svr_id,
			"zcard", RanklistRedisMng.get_tpl_rankstable_key(rank_key, region))

	if not result then
		filelog.sys_error("RanklistRedisMng.update_realrank_tostablerank error")
		return nil
	end

	return rk
end



-- @des    获得
function RanklistRedisMng.getmax_cut_size(rank_key)
	local rk = ranklistcfg[rank_key].cut_size
	return rk
end

-- @des    计算离刷新时间还有多久
function RanklistRedisMng.get_refreshtime(reftime)	
	local  Weekstr, H, MM, SS = string.match(reftime, "(%S+)%s+(%d+):(%d+):(%d+)")
	if Weekstr == nil or H == nil or MM == nil or SS == nil then
		return 0
	end

	local now = timetool.get_time()
	local temp_date = os.date("*t", now)

	local temp_wday = timetool.get_wday(temp_date.wday)
	local day = tonumber(Weekstr)

	local recent_day = 7
	local diff_day = 0
		
	if day ~= 0 then
		diff_day = (day - temp_wday)%7
	end

	temp_date.hour = H
	temp_date.min = MM
	temp_date.sec = SS	
	temp_date.day = temp_date.day + diff_day

	local interval = os.time(temp_date) - timetool.get_time()
	if interval < 0 and day ~= 0 then
		temp_date.day = temp_date.day + recent_day
		interval = os.time(temp_date) - timetool.get_time()
	else
		temp_date.day = temp_date.day + 1
		interval = os.time(temp_date) - timetool.get_time()		
	end

	return interval
end



-- @des    获取重置刷新时间
-- @author lion
function RanklistRedisMng.get_reftime(rank_key, region)
	local result,rk = redisdao.query_data(msghelper:get_conf().ranklistdb.svr_id,
			"get",RanklistRedisMng.get_tpl_ref_key(rank_key, region))

	if not result then
		filelog.sys_error("RanklistRedisMng.update_realrank_tostablerank error")
		return 0
	end

	if type(rk) == "string" then
		rk = tonumber(rk)
	end

	if rk == nil then
		rk = 0
	end
	return rk
end


-- @des    保存重置刷新时间
-- @author lion
function RanklistRedisMng.save_reftime(rank_key,reftime, region)
	redisdao.save_data(msghelper:get_conf().ranklistdb.svr_id,
			"set",RanklistRedisMng.get_tpl_ref_key(rank_key, region),reftime)
end

return RanklistRedisMng